package edu.pku.sei.mte.compositetrans;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.ecore.resource.Resource;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import agg.xt_basis.BaseFactory;
import agg.xt_basis.GraGra;
import edu.pku.sei.mte.compositetrans.agg.AGGController;
import edu.pku.sei.mte.compositetrans.configuration.ModelSpec;
import edu.pku.sei.mte.compositetrans.configuration.TransDescriptor;
import edu.pku.sei.mte.compositetrans.flow.FlowController;
import edu.pku.sei.mte.compositetrans.flow.FlowNode;
import edu.pku.sei.mte.compositetrans.flow.InitialNode;
import edu.pku.sei.mte.compositetrans.flow.TActionNode;
import edu.pku.sei.mte.compositetrans.flow.TDecisionNode;
import edu.pku.sei.mte.compositetrans.mediniqvt.MediniQVTController;
import edu.pku.sei.mte.compositetrans.pkumt.PKUMTController;
import edu.pku.sei.mte.mtemodel.model.MModelGraph;
import edu.pku.sei.mte.serialization.EcoreLoader;
import edu.pku.sei.mte.serialization.EcoreXMISaver;
import edu.pku.sei.mte.utilities.ModelFormat;
import edu.pku.sei.mte.utilities.Utility;

public class CompositeTController extends TController {

	public CompositeTController(ModelFormat mf, Element root) {
		super(mf, root);
		configTrans(root);
	}

	private FlowController flowController = new FlowController();
	private Map<Integer, FlowNode> FlowNodesMap = new HashMap<Integer, FlowNode>();
	
	@Override
	protected boolean init() {
		return true;
	}

	@Override
	protected boolean loadModel(TResult result, ModelSpec ms) {
		return true;
	}

	@Override
	protected boolean loadModel(ModelSpec ms) {
		return true;
	}

	@Override
	protected boolean saveModel() {
		return false;
	}
	
	@Override
	public boolean launch() throws Exception {
		return true;
	}

	@Override
	public TResult transform() throws Exception{
		flowController.launch();
		return null;
	}
	
	public TController getTController(String s){
		int i = Integer.parseInt(s);
		if(FlowNodesMap.containsKey(i)){
			FlowNode fn = FlowNodesMap.get(i);
			if(fn instanceof TActionNode)
				return ((TActionNode)fn).getAction();
			else return null;
		}
		if(container != null)
			return container.getTController(s);
		else return null;
	}
	
	protected void configTrans(Element root){
		if(root.getTagName().equals(TransDescriptor.TRANS_FLOW)){
			NodeList nl = root.getChildNodes();
			List<Element> el = new LinkedList<Element>();
			for(int i=0;i<nl.getLength();i++){
				Node n = nl.item(i);
				if(n.getNodeType()!=Node.ELEMENT_NODE)
					continue;
				Element e = (Element) n;
				initFlowNode(e);
				el.add(e);
			}
			for(Element e: el){
				FlowNode n = FlowNodesMap.get(getNodeId(e));
				n.load(e, FlowNodesMap);
				if(n instanceof TActionNode)
					((TActionNode)n).getAction().setContainer(this);
				else if(n instanceof TDecisionNode)
					((TDecisionNode)n).setContainer(this);
			}
		}
	}
	
	private void initFlowNode(Element e){
		if(e.getTagName().equals("initial")){
			InitialNode firstNode = FlowController.createInitialNode();
			flowController.setFirstNode(firstNode);
			FlowNodesMap.put(getNodeId(e), firstNode);
		}
		else if(e.getTagName().equals("final"))
			FlowNodesMap.put(getNodeId(e), FlowController.createActivityFinal());
		else if(e.getTagName().equals("fork"))
			FlowNodesMap.put(getNodeId(e), FlowController.createForkNode());
		else if(e.getTagName().equals("join"))
			FlowNodesMap.put(getNodeId(e), FlowController.createJoinNode());
		else if(e.getTagName().equals("taction")){
			FlowNodesMap.put(getNodeId(e), FlowController.createTActionNode());
		}
		else if(e.getTagName().equals("tdecision"))
			FlowNodesMap.put(getNodeId(e), FlowController.createTDecisionNode());
	}
	
	private int getNodeId(Element e){
		return Integer.parseInt(e.getAttribute("id"));
	}
	
	public FlowController getFlowController() {
		return flowController;
	}

	public void setFlowController(FlowController flowController) {
		this.flowController = flowController;
	}

	public static void separateTrans() throws Exception{
		PKUMTController c = new PKUMTController(Utility.loadXML("pkumt\\pkumt.xml"));
		c.transform();
		BaseFactory bf = BaseFactory.theFactory();
		GraGra graphGrammar = bf.createGraGra();
		graphGrammar.load("BPMNtoBPEL\\BPMNtoBPEL.ggx");
		Utility.PKUMT2GGX(c.result, graphGrammar);
		graphGrammar.save("ctest\\aggtrans.ggx");
		AGGController ac = new AGGController(Utility.loadXML("agg\\agg.xml"));
		ac.transform();
		graphGrammar = bf.createGraGra();
		graphGrammar.load("ctest\\aggBPEL.ggx");
		MModelGraph model = Utility.GGX2PKUMT(graphGrammar, EcoreLoader.getEcoreLoader("BPMNBPELGraph", "BPMNtoBPEL\\BPMNBPELGraph.ecore").load());
		new EcoreXMISaver().save(model, "ctest\\BPMNBPELGraph.xmi");
		
//		MediniQVTController mc = new MediniQVTController(Utility.loadXML("uml2rdbms\\uml2rdbms.xml"));
		MediniQVTController mc = new MediniQVTController(Utility.loadXML("mediniqvt\\mediniqvt.xml"));
		mc.transform();
		((Resource)mc.result.targetModel).save(Collections.EMPTY_MAP);
		System.out.println("haha");
	}
	public static void main(String[] args) throws Exception {
		CompositeTController cc = new CompositeTController(ModelFormat.EMF, Utility.loadXML("UMLADtoBPEL\\UMLADtoBPEL.xml"));
		cc.transform();
//		separateTrans();
	}
}
